/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "gpio.h"
#include "rtc.h"
#include "usart.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define STR_MATCH(buf, literal)                                                \
  (memcmp((buf), (literal), sizeof(literal) - 1) == 0)
#define RTC_FREQ (32768 / 2 * 1000U) // mHz
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
// 蓝牙接收缓冲区
uint8_t rx_data[256] = {0};
// 蓝牙接收长度
volatile uint8_t size = 0;
// 0：等待蓝牙连接； 1：蓝牙接收到数据； 2：蓝牙数据已处理； 3：蓝牙断开连接
volatile uint8_t state = 0;
// 天线输出比特流
volatile char wave_data[64] = "01011000010010100101100101010101";
// 天线输出比特流计数
volatile uint8_t mescnt = 0;
// 天线输出比特流重复次数
volatile uint32_t num = 128;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
// 不定长数据接收完成回调函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
  if (huart->Instance == USART1) {
    // 进入蓝牙接收到数据状态
    state = 1;
    size = Size;
    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_data, sizeof(rx_data));
    __HAL_DMA_DISABLE_IT(huart1.hdmarx, DMA_IT_HT);
  }
}
void sleep() {
  HAL_SuspendTick();
  HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  HAL_ResumeTick();
}
void stop() {
  HAL_SuspendTick();
  HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  SystemClock_Config();
  HAL_ResumeTick();
}
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) {
  static uint32_t count = 0;
  count++;
  if (count >= 1200) {
    if (state == 0) {
      state = 3;
      HAL_UART_DeInit(&huart1);
      HAL_GPIO_WritePin(BLESW_GPIO_Port, BLESW_Pin, GPIO_PIN_SET);
    }
  }
  mescnt += (count % num == 0);
  if (wave_data[mescnt] == '\0') {
    mescnt = 0;
  }
  if (wave_data[mescnt] == '1')
    HAL_GPIO_TogglePin(WAVE_GPIO_Port, WAVE_Pin);
}
/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void) {

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick.
   */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
  HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_data, sizeof(rx_data));
  __HAL_DMA_DISABLE_IT(huart1.hdmarx, DMA_IT_HT);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  const char DISCONmessage[] = "discon";
  const char FREQmessage[] = "freq";
  const char MESmessage[] = "mes";
  const char NUMmessage[] = "num";

  while (1) {
    if (state == 1) {
      if (STR_MATCH(rx_data, DISCONmessage)) {
        state = 3;
        HAL_UART_DMAStop(&huart1);
        HAL_UART_DeInit(&huart1);
        HAL_GPIO_WritePin(BLESW_GPIO_Port, BLESW_Pin, GPIO_PIN_SET);
      } else if (STR_MATCH(rx_data, FREQmessage)) {
        state = 2;
        char *endptr;
        rx_data[size] = '\0';
        uint32_t freq =
            strtol((char *)rx_data + sizeof(FREQmessage) - 1, &endptr, 10) * 2;
        if (freq == 0)
          freq = 1;
        if (*endptr == '\0') {
          uint32_t wakeup_counter = RTC_FREQ / freq;
          if (wakeup_counter > 0xFFFF)
            wakeup_counter = 0xFFFF;
          // 改变 rtc 中断频率
          HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
          HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_counter,
                                      RTC_WAKEUPCLOCK_RTCCLK_DIV2);
        }
      } else if (STR_MATCH(rx_data, MESmessage)) {
        state = 2;
        rx_data[size] = '\0';
        for (uint8_t i = sizeof(MESmessage) - 1; i < size; i++) {
          if (rx_data[i] != '0' && rx_data[i] != '1') {
            break;
          }
          wave_data[i - (sizeof(MESmessage) - 1)] = rx_data[i];
        }
        wave_data[size - (sizeof(MESmessage) - 1)] = '\0';
        mescnt = 0;
      } else if (STR_MATCH(rx_data, NUMmessage)) {
        state = 2;
        rx_data[size] = '\0';
        char *endptr;
        num = strtol((char *)rx_data + sizeof(NUMmessage) - 1, &endptr, 10);
      }
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    if (state == 3) {
      stop();
    } else {
      sleep();
    }
  }
  /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void) {
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage
   */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Configure LSE Drive Capability
   */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType =
      RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1 | RCC_PERIPHCLK_RTC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void) {
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1) {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line) {
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line
     number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file,
     line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
